﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Synthesis;
using System.Text;
using UniRlv.COL;
using UniRlv.Utility.AppLib;

namespace UniRlv.Utility
{
    public static class CodePrcUtility
    {
        public static bool DUP_CHECK = true;
        public static bool PRODUCT_CHECK = true;
        public static bool PRODUCT_CHECKLevel1 = true;
        public static string CODEREG = "";
        public static bool PICK_TWICE = true;

        static List<UniScanner> m_arrUniScanner = new List<UniScanner>();
        static object objSave = new object();

        public static en_code_prc SaveCode(LineDevice dev, string code, ref string strMsg)
        {

            if (dev.getCode == 0 || dev.state == 0 || dev.stationNumber > PublicObject.CurTask.tagLevel)//查看设备合法性
            {
                strMsg = string.Format("入库失败：设备状态错误，getCode={0}, state={1}, station={2}" ,dev.getCode, dev.state, dev.stationNumber);
                return en_code_prc.CP_INVALID_PARA;
            }

            if (code.Length == 1)
            {
                strMsg = "入库失败：解码失败";
                return en_code_prc.CP_PICK;
            }

            #region 是否需要功能采集器处理
	        if(dev.deviceType== (int)in_device_type.IDT_UNI_SCANER || dev.deviceType== (int)in_device_type.IDT_FUNC_SCANNER)
	        {//综合功能采集器，可能才采集到功能码
		        en_uniscanner_prc_state ps;
		        for (int i=0; i<m_arrUniScanner.Count; i++)
		        {
			        if (dev.ID == m_arrUniScanner[i].GetDev().ID)
			        {
				        ps = m_arrUniScanner[i].PutCode(code);

				        if (ps==en_uniscanner_prc_state.CODE_OK)
				        {//正常入库扫描，按正常处理流程
					        break;
				        }
				        else if(ps==en_uniscanner_prc_state.CODE_OPR_OK)
				        {//处理操作结果

                            try
                            {
                                en_code_prc cp = DealWithOpr(m_arrUniScanner[i].GetOprType(), m_arrUniScanner[i].m_saOpr, ref strMsg);
                                m_arrUniScanner[i].Reset();
                                return cp;
                            }
                            catch (Exception ex)
                            {
                                strMsg = "手持操作失败：" + ex.Message;
                                m_arrUniScanner[i].Reset();
                                return en_code_prc.CP_PRC_NORMAL;
                            }


				        }
				        else
				        {//处理操作过程提示
                            if (m_arrUniScanner[i].m_enSteps == en_uniscanner_steps.STEPS_C_CHECK2 && m_arrUniScanner[i].m_saOpr.Count>1)
                            {//连续查询一二级关联
                                DealWithOpr(m_arrUniScanner[i].GetOprType(), m_arrUniScanner[i].m_saOpr, ref strMsg);
                                return en_code_prc.CP_STEPS;
                            }
                            else if (m_arrUniScanner[i].m_enSteps == en_uniscanner_steps.STEPS_QUERY_SINGLE && m_arrUniScanner[i].m_saOpr.Count > 0)
                            {//连续查询码状态
                                DealWithOpr(m_arrUniScanner[i].GetOprType(), m_arrUniScanner[i].m_saOpr, ref strMsg);
                                return en_code_prc.CP_STEPS;
                            }
                            else
                            {
                                strMsg = m_arrUniScanner[i].GetLastError();
                                return en_code_prc.CP_STEPS;
                            }
					        
				        }
			        }
		        }

	        }

#endregion

            string code24Bit = string.Empty;

            if (dev.deviceType == (int)in_device_type.IDT_OCR_CAMERA)
            {//OCR相机读取关联码，码内容不一定包含品名和文号，位数也不一定多少位
                code24Bit = code;
            }
            else
            {
                if (dev.twiceScan == 1)
                {//二次采集不检查品名和文号
                    code24Bit = AppHelper.SYZSGet24BitFromCodeNoCheck(code);
                    if (string.IsNullOrEmpty(code24Bit))
                    {
                        strMsg = string.Format("入库失败：原始码={0}，无法获取有效追溯码数据", code);
                        return en_code_prc.CP_PRODUCT_ERR;
                    }
                }
                else
                {
                    if (!AppHelper.SYZSGet24BitFromCode(ref code24Bit, code, dev.stationNumber))
                    {
                        strMsg = string.Format("入库失败：原始码={1}，{0}", code24Bit, code);
                        return en_code_prc.CP_PRODUCT_ERR;
                    }

                }
            }



                
		    if (dev.deviceType==(int)in_device_type.IDT_OCR_CAMERA)
			{
				return SaveCodeLevelOneX(dev, code24Bit, ',', ref strMsg);
			} 
			else if(dev.deviceType==(int)in_device_type.IDT_LEVEL_CAMERA)
			{
				return SaveCodeLevelXX(dev, code24Bit, ',', ref strMsg);
			}
			else
			{
				return SaveCode24Bit(dev, code24Bit, ref strMsg);
			}


        }


        #region 保存码
        

        /// <summary>
        /// 保存各级码
        /// </summary>
        /// <param name="dev"></param>
        /// <param name="code"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        private static en_code_prc SaveCode24Bit(LineDevice dev, string code, ref string strMsg)
        {

	        try
	        {
                CodeInfo stCode;

		        if(!CheckDuplicate(code) || dev.twiceScan == 1)
		        {
                    if (!JudgeCodeValid(code))
                    {
                        strMsg = string.Format("入库失败：码不属于数据源数据，码内容={0}", code);
                        return en_code_prc.CP_INVALID_PARA;
                    }

                    if (dev.twiceScan == 1)
                    {
                        stCode = FindCode(code);

                        if (stCode == null)
                        {
                            strMsg = string.Format("入库失败：尚未一次扫描，不能直接二次扫描，码内容={0}", code);
                            return en_code_prc.CP_INVALID_PARA;
                        }
                        else
                        {
                            if (stCode.stationNumber != dev.stationNumber)
                            {
                                strMsg = string.Format("入库失败：不是{1}级码，不允许二次扫描，码内容={0}", code, dev.stationNumber);
                                return en_code_prc.CP_INVALID_PARA;
                            }
                            else
                            {
                                if (PICK_TWICE && stCode.serialNumber2>0)
                                {
                                    strMsg = string.Format("入库失败：码已二次扫描，不能重复入库，{0}，二次扫描序号：{1}", stCode.code, FindCodePos2(stCode) + 1);
                                    return en_code_prc.CP_DUPLICATE;
                                }
                                else
                                {
                                    stCode.serialNumber2 = GetAvailableSN2(2);
                                    return en_code_prc.CP_NORMAL;
                                }
                                
                            }
                            
                        }

                    }
                    else
                    {
                        stCode = new CodeInfo();

                        stCode.code = code;

                        stCode.sourceID = 0;

                        stCode.stationNumber = 0;

                        stCode.serialNumber = 0;

                        stCode.subDeviceNumber = 0;

                        stCode.serialNumber2 = 0;

                        stCode.taskID = 0;

                        stCode.codeState = 0;

                        stCode.packageState = 0;

                        stCode.printTimes = 0;

                        //TRACE("query scan code=%dms\n", newTicks-oldTicks);

                        lock (objSave)
                        {
                            if (JudgeCodeStateUsefull(stCode.codeState))
                            {
                                stCode.codeState = (int)code_state.CS_SCANED;
                                stCode.packageState = (int)package_state.PS_NORMAL;
                                stCode.inTime = DateTime.Now;
                                stCode.stationNumber = dev.stationNumber;
                                stCode.taskID = PublicObject.CurTask.ID;
                                stCode.subDeviceNumber = dev.subDeviceNumber;

                                IList<CodeInfo> li = PublicObject.arrCode1;

                                switch (stCode.stationNumber)
                                {
                                    case 1:
                                        li = PublicObject.arrCode1;break;
                                    case 2:
                                        li = PublicObject.arrCode2; break;
                                    case 3:
                                        li = PublicObject.arrCode3; break;
                                    case 4:
                                        li = PublicObject.arrCode4; break;
                                }

                                if (dev.stationNumber == 1 && PublicObject.arrCode1.bMergeOne)
                                {//分道

                                    int cnt = PublicObject.arrCode1.GetCount(dev.subDeviceNumber);

                                    if (cnt == 0)
                                    {
                                        stCode.serialNumber = dev.subDeviceNumber + 1;//line0: 1 3 5……   line1:2 4 6 ……
                                    }
                                    else
                                    {
                                        stCode.serialNumber = PublicObject.arrCode1.GetTop(dev.subDeviceNumber).serialNumber + 2;
                                    }

                                    stCode.serialNumber2 = 0;

                                    PublicObject.arrCode1.Add(dev.subDeviceNumber, stCode);
                                }
                                else
                                {
  
                                    stCode.serialNumber = GetAvailableSN(stCode.stationNumber);

                                    stCode.serialNumber2 = 0;

                                    li.Add(stCode);
                                }

                                //PublicObject.CodeScanned.Add(stCode.code);

                                return en_code_prc.CP_NORMAL;

                            }
                            else
                            {

                                if (stCode.codeState == (int)code_state.CS_PRINTED)
                                {
                                    strMsg = string.Format("入库失败：码已打印，不能重复入库，{0}", stCode.code);
                                    return en_code_prc.CP_DUPLICATE;
                                }
                                else if (stCode.codeState == (int)code_state.CS_SCANED || stCode.codeState == (int)code_state.CS_IMP)
                                {
                                    strMsg = string.Format("入库失败：码已扫描，不能重复入库，{0}", stCode.code);
                                    return en_code_prc.CP_DUPLICATE;
                                }
                                else if (stCode.codeState == (int)code_state.CS_DISCARDED)
                                {
                                    strMsg = string.Format("入库失败：码已废弃，不允许入库，{0}", stCode.code);
                                    return en_code_prc.CP_INVALID_PARA;
                                }
                                else if (stCode.codeState == (int)code_state.CS_QJ)
                                {
                                    strMsg = string.Format("入库失败：码已取检，不允许入库，{0}", stCode.code);
                                    return en_code_prc.CP_INVALID_PARA;
                                }
                                else
                                {
                                    strMsg = string.Format("入库失败：非法码状态{0}，不允许入库，{1}", stCode.codeState, stCode.code);
                                    return en_code_prc.CP_INVALID_PARA;
                                }
                            }
                        }

                    }

		        } 
		        else
		        {
			        strMsg = string.Format("入库失败：码已扫描，不能重复入库，{0}", code);
			        return en_code_prc.CP_DUPLICATE;
		        }
	        }
	        catch(Exception exp)
	        {
		        strMsg = "入库失败：" + exp.Message ;
		        return en_code_prc.CP_DB_ERR;
	        }

        }


        /// <summary>
        /// 保存打印码
        /// </summary>
        /// <param name="fullCode">条码数据</param>
        /// <param name="station">码级别</param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static en_code_prc SavePrintCode(string fullCode, int station, ref string strMsg)
        {

            string code24Bit = string.Empty;

            if (!AppHelper.SYZSGet24BitFromCode(ref code24Bit, fullCode, station))
            {
                strMsg = string.Format("打印数据入库失败：原始码={1}，{0}", code24Bit, fullCode);
                return en_code_prc.CP_PRODUCT_ERR;
            }

            try
            {
                CodeInfo stCode;

                if (!CheckDuplicate(code24Bit))
                {

                    stCode = new CodeInfo();

                    stCode.code = code24Bit;

                    stCode.sourceID = 0;

                    stCode.stationNumber = 0;

                    stCode.serialNumber = 0;

                    stCode.subDeviceNumber = 0;

                    stCode.serialNumber2 = 0;

                    stCode.taskID = 0;

                    stCode.codeState = 0;

                    stCode.packageState = 0;

                    stCode.printTimes = 0;

                    //TRACE("query scan code=%dms\n", newTicks-oldTicks);

                    lock (objSave)
                    {
                        if (JudgeCodeStateUsefull(stCode.codeState))
                        {
                            stCode.codeState = (int)code_state.CS_PRINTED;
                            stCode.packageState = (int)package_state.PS_NORMAL;
                            stCode.inTime = DateTime.Now;
                            stCode.stationNumber = station;
                            stCode.taskID = PublicObject.CurTask.ID;
                            stCode.subDeviceNumber = 0;

                            IList<CodeInfo> li = PublicObject.arrCode1;

                            switch (stCode.stationNumber)
                            {
                                case 1:
                                    li = PublicObject.arrCode1; break;
                                case 2:
                                    li = PublicObject.arrCode2; break;
                                case 3:
                                    li = PublicObject.arrCode3; break;
                                case 4:
                                    li = PublicObject.arrCode4; break;
                            }


                            stCode.serialNumber = GetAvailableSN(stCode.stationNumber);

                            stCode.serialNumber2 = 0;

                            li.Add(stCode);

                            //PublicObject.CodeScanned.Add(stCode.code);

                            return en_code_prc.CP_NORMAL;

                        }
                        else
                        {

                            if (stCode.codeState == (int)code_state.CS_PRINTED)
                            {
                                strMsg = string.Format("打印码入库失败：码已打印，不能重复入库，{0}", stCode.code);
                                return en_code_prc.CP_DUPLICATE;
                            }
                            else if (stCode.codeState == (int)code_state.CS_SCANED || stCode.codeState == (int)code_state.CS_IMP)
                            {
                                strMsg = string.Format("打印码入库失败：码已扫描，不能重复入库，{0}", stCode.code);
                                return en_code_prc.CP_DUPLICATE;
                            }
                            else if (stCode.codeState == (int)code_state.CS_DISCARDED)
                            {
                                strMsg = string.Format("打印码入库失败：码已废弃，不允许入库，{0}", stCode.code);
                                return en_code_prc.CP_INVALID_PARA;
                            }
                            else if (stCode.codeState == (int)code_state.CS_QJ)
                            {
                                strMsg = string.Format("打印码入库失败：码已取检，不允许入库，{0}", stCode.code);
                                return en_code_prc.CP_INVALID_PARA;
                            }
                            else
                            {
                                strMsg = string.Format("打印码入库失败：非法码状态{0}，不允许入库，{1}", stCode.codeState, stCode.code);
                                return en_code_prc.CP_INVALID_PARA;
                            }
                        }

                    }

                }
                else
                {
                    strMsg = string.Format("打印码入库失败：码已扫描，不能重复入库，{0}", code24Bit);
                    return en_code_prc.CP_DUPLICATE;
                }
            }
            catch (Exception exp)
            {
                strMsg = "入库失败：" + exp.Message;
                return en_code_prc.CP_DB_ERR;
            }

        }

        /// <summary>
        /// 判断数据是否可以打印
        /// </summary>
        /// <param name="fullCode"></param>
        /// <param name="station"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool IfCodeCanPrint(string fullCode, int station, ref string strMsg)
        {
            string code24Bit = string.Empty;

            if (!AppHelper.SYZSGet24BitFromCode(ref code24Bit, fullCode, station))
            {
                strMsg = string.Format("打印数据不可用，无法获取有效数据：原始码={1}，{0}", code24Bit, fullCode);
                return false; ;
            }

            if(CheckDuplicate(code24Bit))
            {
                strMsg = string.Format("码已入库，无法打印：原始码={1}，{0}", code24Bit, fullCode);
                return false; ;
            }

            return true;
        }

        /// <summary>
        /// [2018-11-18 Connortao]
        /// 方法描述：一次保存x个x级码，适合级别采集器，暂时不支持二次扫描
        /// 参数描述：code包含nNum个码，采用p符号号分割
        /// </summary>
        private static en_code_prc SaveCodeLevelXX(LineDevice dev,string code, char p,ref string strMsg)
        {
 	        throw new NotImplementedException();
        }

        /// <summary>
        /// [2016-11-18 Connortao]
        /// 方法描述：一次保存x个一级码，可以兼容原始码或者关联码，适合OCR相机
        /// 参数描述：code包含nNum个码，采用p符号号分割
        /// </summary>
        private static en_code_prc SaveCodeLevelOneX(LineDevice dev,string code24Bit,char p,ref string strMsg)
        {

	        string[] saCode10;
	        string sTmp;
	        int nNum;

	        long oldTicks, newTicks;
	        oldTicks = DateTime.Now.TimeOfDay.Ticks/10000;

	        saCode10 = dev.initString.Split(new char[]{','});
	        if (saCode10.Length==3)
	        {//计算一级码数据量
		        nNum = Convert.ToInt32(saCode10[2]);
	        }
	        else
		        nNum = 10;


	        saCode10 = code24Bit.Split(new char[]{p});

	        if (saCode10.Length!=nNum)
	        {
		        strMsg = string.Format("入库失败。一级码码数量为{0}个。入库失败：一级码码数量包含{1}个，不足{2}个，码内容={3}", nNum, saCode10.Length, nNum, code24Bit);
		        return en_code_prc.CP_ERR;
	        }

	        for (int i=0; i<nNum; i++)
	        {
		        sTmp = saCode10[i];
		        if (sTmp.Equals("noread", StringComparison.OrdinalIgnoreCase))
		        {
			        strMsg = "入库失败。解码失败：" + code24Bit;
			        return en_code_prc.CP_PICK;
		        }


	        }

	        //查询关联码
	        List<CodeRltInfo> arrRlt = PublicObject.CodeRlt.Where((c)=>
            {
                return saCode10.Contains(c.rltCode);
            }).ToList();

            if (arrRlt==null)
            {
                strMsg = $"入库失败。未找到追溯码";
                return en_code_prc.CP_ERR;
            }
            else if (arrRlt.Count != nNum)
            {
                strMsg = $"入库失败。找到的追溯码数量为{arrRlt.Count}，与关联码数量不一致";
                return en_code_prc.CP_ERR;
            }

	        //是否都是未关联码
	        int nAlready = 0;
	        int nPos, nPos2;
	        CodeInfo stCode;
	        List<CodeInfo> arrCode = new List<CodeInfo>();

	        sTmp = string.Empty;

            //关联码可以重复用，不检查是否已经用过，2020-12-30
            //for(int i=0; i<nNum; i++)
            //{
            // if (arrRlt[i].codeState!=0)
            // {
            //  nAlready++;
            //           stCode = FindCode(arrRlt[i].code);
            //  nPos = FindCodePos(stCode);

            //  if (PublicObject.bSecond)
            //  {
            //   if(nPos>=0 && nPos/nNum<PublicObject.arrCode2.Count)
            //   {

            //    nPos2 = FindCodePos2(PublicObject.arrCode2[nPos/nNum]) + 1;//从1开始	
            //   }
            //   else
            //    nPos2 = -1;
            //  } 
            //  else
            //  {
            //   if(nPos>=0 && nPos/nNum<PublicObject.arrCode2.Count)
            //    nPos2 = nPos/nNum + 1;
            //   else
            //    nPos2 = -1;
            //  }

            //  if(nAlready==1)
            //  {
            //   strMsg = string.Format("入库失败。关联码失败，关联码已入库。入库失败：关联码已入库，关联码内容={0}，24位码内容={1}，位置[{2}]，父码位置{3}]", 
            //    arrRlt[i].rltCode, arrRlt[i].code, nPos>=0?nPos+1:nPos, nPos2);
            //  }
            //  else
            //  {
            //   sTmp = string.Format("    关联码内容={0}，24位码内容={1}，位置[{2}]，父码位置[{3}]", 
            //    arrRlt[i].rltCode, arrRlt[i].code, nPos>=0?nPos+1:nPos, nPos2);
            //   strMsg += sTmp;
            //  }

            // }
            //}

            //   if (nAlready != 0)
            //   {
            //       return en_code_prc.CP_ERR;
            //   }

            //更新码

            for (int i=0; i<nNum; i++)
	        {
                stCode = new CodeInfo();
		        stCode.code = arrRlt[i].code;

		        try
		        {
                    if(!AppHelper.SYZSCheck24Bit(stCode.code))
                    {
                        strMsg = string.Format("入库失败：条码非法，原始码={0}，瓶盖码={1}", stCode.code, arrRlt[i].code);
                        return en_code_prc.CP_INVALID_PARA;
                    }

                    if (!JudgeCodeValid(stCode.code))
                    {
                        strMsg = string.Format("入库失败：码不属于数据源数据，码内容={0}", stCode.code);
                        return en_code_prc.CP_INVALID_PARA;
                    }

                    //if (m_dbOneLevel.QueryScanCode(stCode, ws.dwaSourceList, m_bUseTmpTable))
                    if (!CheckDuplicate(stCode.code))
			        {
				        stCode.sourceID = 0;

				        stCode.stationNumber = 0;

				        stCode.serialNumber = 0;

				        stCode.subDeviceNumber = 0;

				        stCode.serialNumber2 = 0;

				        stCode.taskID = 0;

				        stCode.codeState = 0;

				        stCode.packageState = 0;

				        stCode.printTimes = 0;

				        if (JudgeCodeStateUsefull(stCode.codeState))
				        {
        #region 填写扫描码信息
                            
					        stCode.codeState = (int)code_state.CS_SCANED;
                            
					        stCode.packageState = (int)package_state.PS_NORMAL;

					        stCode.inTime = DateTime.Now;

					        if(PublicObject.arrCode1.Count==0)
						        stCode.serialNumber = i+1;
					        else
					        {
                                stCode.serialNumber = GetAvailableSN(1) + i;
					        }

					        stCode.serialNumber2 = 0;

					        stCode.stationNumber = dev.stationNumber;
					        stCode.taskID = PublicObject.CurTask.ID;
					        stCode.subDeviceNumber = dev.subDeviceNumber;

					        arrCode.Add(stCode);
                            //PublicObject.CodeScanned.Add(stCode.code);
                            #endregion

                        } 
				        else
				        {
                            
                            if(!DUP_CHECK)
					            return en_code_prc.CP_NORMAL;

					        if (stCode.codeState==(int)code_state.CS_PRINTED)
					        {
						        strMsg = string.Format("入库失败。码已打印，不能重复入库。入库失败：码已打印，不能重复入库，{0}", stCode.code);
						        return en_code_prc.CP_DUPLICATE;
					        }
					        else if(stCode.codeState==(int)code_state.CS_SCANED || stCode.codeState==(int)code_state.CS_IMP )
					        {
						        strMsg = string.Format("入库失败。码已扫描，不能重复入库。码已扫描，不能重复入库，{0}", stCode.code);
						        return en_code_prc.CP_DUPLICATE;
					        }
					        else if(stCode.codeState==(int)code_state.CS_DISCARDED)
					        {
						        strMsg = string.Format("入库失败。码已废弃，不允许入库。入库失败：码已废弃，不允许入库，{0}", stCode.code);
						        return en_code_prc.CP_INVALID_PARA;
					        }
					        else if(stCode.codeState==(int)code_state.CS_QJ)
					        {
						        strMsg = string.Format("入库失败。码已取检，不允许入库。入库失败：码已取检，不允许入库，{0}", stCode.code);
						        return en_code_prc.CP_INVALID_PARA;
					        }
					        else
					        {
						        strMsg = string.Format("入库失败。非法码状态，不允许入库。入库失败：非法码状态{0}，不允许入库，{1}", stCode.codeState, stCode.code);
						        return en_code_prc.CP_INVALID_PARA;
					        }
				        }

			        } 
			        else
			        {
				        strMsg = string.Format("入库失败。码已扫描，不能重复入库。码已扫描，不能重复入库，{0}", stCode.code);
				        return en_code_prc.CP_DUPLICATE;
			        }
		        }
		        catch(Exception exp)
		        {
			        strMsg = "入库失败。数据库操作异常。入库失败：系统异常，数据库操作错误";
			        return en_code_prc.CP_DB_ERR;
		        }
	        }

            if (dev.subDeviceNumber == 0)
            {
                PublicObject.arrCode1.AddRange1(arrCode);
            }
            else
            {
                PublicObject.arrCode1.AddRange2(arrCode);
            }

            int idx;
            foreach (var item in arrRlt)
            {
                idx = PublicObject.CodeRlt.IndexOf(item);
                PublicObject.CodeRlt[idx].codeState = (int)code_state.CS_SCANED;
            }

            newTicks = DateTime.Now.TimeOfDay.Ticks / 10000;
	        Console.WriteLine("SaveCodeLevelOneX={0}ms\n", newTicks-oldTicks);

            return en_code_prc.CP_NORMAL;
        } 

        #endregion


        #region 快捷处理（功能码处理）

        private static en_code_prc DealWithOpr(en_uniscanner_steps step, List<string> sa, ref string strMsg)
        {//@@@。@@@。@@@ 三部分：客显状态。客显提示。电脑工位信息提示
            string code = string.Empty;

            for (int i = 0; i < sa.Count; i++)
            {
                //改成不检查品名和文号：2020-02-04
                code = AppHelper.SYZSGet24BitFromCodeNoCheck(sa[i]);
                if(string.IsNullOrEmpty(code))
                {
                    strMsg = string.Format("操作失败，条码非法：{0}，{1}", code, sa[i]);
                    return en_code_prc.CP_INVALID_PARA;
                }

                sa[i] = code;//转换成24位
            }

            bool bRes;

            switch (step)
            {
                case en_uniscanner_steps.STEPS_DELETE:
                case en_uniscanner_steps.STEPS_DELETE_BATCH:
                    bRes = DeleteInBatch(sa, ref strMsg); break;
                case en_uniscanner_steps.STEPS_DELETE_PACKAGE:
                    bRes = DeletePackage(sa[0], ref strMsg); break;
                case en_uniscanner_steps.STEPS_SWITCH2:
                    bRes = SwitchCode(sa, ref strMsg); break;
                case en_uniscanner_steps.STEPS_REPLACE2:
                    bRes = ReplaceCode(sa, ref strMsg); break;
                case en_uniscanner_steps.STEPS_CHECK2:
                    bRes = CheckRlt(sa, ref strMsg); break;
                case en_uniscanner_steps.STEPS_INSERT2:
                    bRes = InsertCode(sa, ref strMsg); break;
                case en_uniscanner_steps.STEPS_QUERY_SINGLE:
                    bRes = QueryCodeState(sa[sa.Count - 1], ref strMsg); break;
                //case en_uniscanner_steps.STEPS_IMPLEMENT:
                //    ASSERT(sa.GetCount()==1);
                //    bRes = Implement(sa.GetAt(0), ref strMsg);break;
                case en_uniscanner_steps.STEPS_DELETE_REMAIN:
                    bRes = SetRemainDelete(ref strMsg); break;
                case en_uniscanner_steps.STEPS_UNBOX_REMAIN:
                    bRes = SetRemainPackageState(package_state.PS_UNBOX, string.Empty, ref strMsg); break;
                case en_uniscanner_steps.STEPS_ZERO_REMAIN:
                    //    ASSERT(sa.GetCount()==1);
                    bRes = SetRemainPackageState(package_state.PS_ZERO, sa[0], ref strMsg); break;
                //case en_uniscanner_steps.STEPS_DELETE_EMPTY:
                //    bRes = DeleteEmpty(ref strMsg);break;
                //case en_uniscanner_steps.STEPS_RESTART:
                //    RestartTask();
                //    ref strMsg.Format(_T("重启任务成功。任务号%-6s，请重新入库。重启任务：任务号为%s"), CCommonBLL::GetTaskEncodeById(ws.curTask._id), CCommonBLL::GetTaskEncodeById(ws.curTask._id));
                //    bRes = TRUE;break;
                //case en_uniscanner_steps.STEPS_SCAN_MANUAL:
                //    bRes = InsertCode21(sa, ref strMsg);break;
                case en_uniscanner_steps.STEPS_REPRINT:
                    bRes = WorkSpace.GetInstance().RePrintOneLabel(sa[0], 1, ref strMsg); break;
                case en_uniscanner_steps.STEPS_C_CHECK2:
                    bRes = CheckRlt(sa[0], sa[sa.Count-1], ref strMsg); break;
                case en_uniscanner_steps.STEPS_DELETE_SEC:
                    bRes = DeleteSec(sa[0], ref strMsg); break;
                default:
                    strMsg = string.Format("操作失败：非法操作码{0}！", step);
                    return en_code_prc.CP_STEPS;
            }

            Console.WriteLine("DealWithOpr: " + strMsg);

            if (bRes)
            {
                if (string.IsNullOrEmpty(strMsg))
                {
                    strMsg = "操作成功";
                }
                
                return en_code_prc.CP_PRC_NORMAL;
            }
            else
                return en_code_prc.CP_STEPS;
        }


        public static bool SetRemainPackageState(package_state ps, string zeroCode, ref string strMsg)
        {
	        bool bRes;

	        if(PublicObject.CurTask.tagLevel==1)
	        {
		        strMsg = "一级关联无剩余包装";
		        return false;
	        }
            else if (PublicObject.CurTask.tagLevel == 2)
	        {
			     bRes =  SetRemainPackageState21(ps, zeroCode, ref strMsg);
	        }
            else if (PublicObject.CurTask.tagLevel == 3)
	        {
                bRes =  SetRemainPackageState31(ps, zeroCode, ref strMsg);
	        }
            else if (PublicObject.CurTask.tagLevel == 4)
            {
                bRes = SetRemainPackageState41(ps, zeroCode, ref strMsg);
            }
	        else
	        {
		        strMsg = "包装级别过高，暂不支持设置剩余包装状态";
		        return false;
	        }

	        if (bRes)
	        {
		        PublicObject.CurTask.packageState = (int)ps;
	        }

	        //Console.Write("散装{0}件产品{1}", m_db.QueryNumByPackageState(17, PS_UNBOX, 1, m_bUseTmpTable));

	        return bRes;
        }

        private static bool SetRemainPackageState41(package_state ps, string zeroCode, ref string strMsg)
        {
            return false;
        }

        private static bool SetRemainPackageState31(package_state ps, string zeroCode, ref string strMsg)
        {
	        CodeInfo stCode, stZero;
	        int nOne=0, nTwo=0;



            int ratio32 = GetCurLevelRatios()[0];
	        int ratio31 = GetCurRatios()[2];
            int ratio21 = ratio31/ratio32;

            
	        if(PublicObject.arrCode3.Count*ratio31>=PublicObject.arrCode1.Count || PublicObject.arrCode3.Count*ratio32>PublicObject.arrCode2.Count )
	        {
		        strMsg = "无未包装产品";
		        return false;
	        }
	        else
	        {
		        if(ps==package_state.PS_ZERO)
		        {
			        			        
                    if(JudgeCodeValid(zeroCode))
			        {
				        strMsg = string.Format("未包装零箱失败：零箱码未导入，{0}", zeroCode);
				        return false;
			        }

			        if (CheckDuplicate(zeroCode))
			        {
				        strMsg = string.Format("未包装零箱失败：零箱码已入库或者非法，{0}", zeroCode);
				        return false;
			        }

                    stZero = new CodeInfo();
                    stZero.code = zeroCode;
			        stZero.packageState = (int)ps;
			        stZero.stationNumber = 2;
			        stZero.codeState = (int)code_state.CS_SCANED;
			        stZero.inTime = DateTime.Now;
			        stZero.taskID = PublicObject.CurTask.ID;
			        stZero.serialNumber = GetAvailableSN(stZero.stationNumber);

                    AddCode(stZero);
		        }

                if (PublicObject.bSecond)
		        {//二次扫描
			        int snSecond;

                    List<CodeInfo> code2 = FindArrayByPos2(PublicObject.arrCode3.Count * ratio32);

                    int pos;
                    int set = 0;//设置的结束位置

                    foreach (CodeInfo item in code2)
                    {
                        pos = PublicObject.arrCode2.IndexOf(item);

                        set = (pos + 1) * ratio21;
                        set = Math.Min(set, PublicObject.arrCode1.Count);
                        nOne += set - pos * ratio21;

                        if (ps == package_state.PS_ZERO)
                        {
                            item.outsideCode = zeroCode;

                            nTwo++;
                        }

                        //顺序设置一级码
                        for (int j = pos * ratio21; j < set * ratio21; j++)
                        {
                            stCode = PublicObject.arrCode1[j];

                            if (ps == package_state.PS_ZERO)
                                stCode.outsideCode = zeroCode;

                            stCode.packageState = (int)ps;
                            nOne++;
                        }
                    }


			        //一级码尾数散装
                    for (int i = PublicObject.arrCode2.Count * ratio21; i < PublicObject.arrCode1.Count && i < (PublicObject.arrCode2.Count + 1) * ratio21; i++)
			        {
                        stCode = PublicObject.arrCode1[i];
                        
				        if(ps==package_state.PS_ZERO)
					        stCode.outsideCode = zeroCode;

				        stCode.packageState = (int)ps;

				        nOne++;
			        }
		        } 
		        else
		        {
			        //顺序设置二级码

                    for (int i = PublicObject.arrCode3.Count * ratio32; i < PublicObject.arrCode2.Count && i < (PublicObject.arrCode3.Count + 1) * ratio32; i++)
			        {
                        stCode = PublicObject.arrCode2[i];

                        if (ps == package_state.PS_ZERO)
					        stCode.outsideCode = zeroCode;

				        stCode.packageState = (int)ps;

				        nTwo++;
			        }

			        //顺序设置一级码
			        for (int i=PublicObject.arrCode3.Count*ratio31; i<PublicObject.arrCode1.Count && i<(PublicObject.arrCode3.Count+1)*ratio31; i++)
			        {
				        stCode = PublicObject.arrCode1[i];
                        
				        if(ps==package_state.PS_ZERO)
					        stCode.outsideCode = zeroCode;

				        stCode.packageState = (int)ps;

				        nOne++;
			        }
		        }


	        }


	        if(ps==package_state.PS_ZERO)
		        strMsg = string.Format("未包装产品零箱成功：零箱含{0}个一级码，{1}个二级码，一二级比值为{2}", nOne, nTwo, ratio21);
	        else
	        {
		        strMsg = string.Format("未包装产品散包装成功：一共{0}个一级码、{1}个二级码散包装化，一二级比值为{2}", nOne, nTwo, ratio21);
	        }

	        return true;
        }

        private static bool SetRemainPackageState21(package_state ps, string zeroCode, ref string strMsg)
        {
	        CodeInfo stCode, stZero;
	        int nOne = 0;

	        int ratio21 = GetCurRatios()[1];

	        if(PublicObject.arrCode2.Count*ratio21>=PublicObject.arrCode1.Count && ps==package_state.PS_ZERO)
	        {
		        strMsg = "无未包装产品";
		        return false;
	        }
	        else
	        {//一级码多

		        if(ps==package_state.PS_ZERO)
		        {
			        if(JudgeCodeValid(zeroCode))
			        {
				        strMsg = string.Format("未包装零箱失败：零箱码未导入，{0}", zeroCode);
				        return false;
			        }

			        if (CheckDuplicate(zeroCode))
			        {
				        strMsg = string.Format("未包装零箱失败：零箱码已入库或者非法，{0}", zeroCode);
				        return false;
			        }

                    stZero = new CodeInfo();
			        stZero.code = zeroCode;
			        stZero.packageState = (int)ps;
			        stZero.stationNumber = 2;
			        stZero.codeState = (int)code_state.CS_SCANED;
			        stZero.inTime = DateTime.Now;
			        stZero.taskID = PublicObject.CurTask.ID;
			        stZero.serialNumber = GetAvailableSN(stZero.stationNumber);

                    AddCode(stZero);
		        }


		        //顺序设置一级码
		        int nBox = PublicObject.arrCode2.Count;
                nBox = Math.Min(PublicObject.arrCode1.Count/ ratio21, nBox);

                for (int i = nBox * ratio21; i < PublicObject.arrCode1.Count; i++)
		        {
                    stCode = PublicObject.arrCode1[i];

                    if (ps == package_state.PS_ZERO)
                        stCode.outsideCode = zeroCode;

			        stCode.packageState = (int)ps;

			        nOne++;
		        }

	        }

            if (ps == package_state.PS_ZERO)
		        strMsg = string.Format("未包装产品零箱成功：零箱含{0}个一级码", nOne);
	        else
	        {
		        strMsg = string.Format("未包装产品散包装成功：一共{0}个一级码散包装化", nOne);
	        }

	        return true;
        }

        public static bool SetRemainDelete(ref string strMsg)
        {
            ProductionTask ws = PublicObject.CurTask;

	        if(ws.tagLevel==1)
	        {
		        strMsg = "一级关联无剩余包装";
		        return false;
	        }
	        else if (ws.tagLevel==2)
	        {
		        return SetRemainDelete21(ref strMsg);
	        } 
	        else if(ws.tagLevel==3)
	        {
		        return SetRemainDelete31(ref strMsg);
	        }
	        else
	        {
		        strMsg = "包装级别过高，暂不支持删除剩余包装";
		        return false;
	        }
        }


        private static bool SetRemainDelete31(ref string strMsg)
        {
	        CodeInfo stCode;
	        int nOne = 0, nTwo=0, nThree=0;

            int ratio32 = GetCurLevelRatios()[0];
	        int ratio31 = GetCurRatios()[2];
            int ratio21 = ratio31/ratio32;
            
	        if(PublicObject.arrCode3.Count*ratio31==PublicObject.arrCode1.Count && PublicObject.arrCode3.Count*ratio32==PublicObject.arrCode2.Count)
	        {
		        strMsg = "无未包装产品";
		        return false;
	        }
	        else
	        {
		        int nMin = PublicObject.arrCode1.Count/ratio31;

                nMin = Math.Min(PublicObject.arrCode2.Count/ratio32, nMin);
                nMin = Math.Min(PublicObject.arrCode3.Count, nMin);

                if (PublicObject.bSecond)
		        {
                    nThree = PublicObject.arrCode3.Count - nMin;
                    PublicObject.arrCode3.RemoveRange(nMin, nThree);

			        //按照二次扫描序号设置一级、二级码
                    List<CodeInfo> codes2 = FindArrayByPos2(nMin * ratio32);
                    nTwo = codes2.Count;

                    if (nTwo > 0)
	                {
                        int pos;
                        int del = 0;//删除的结束位置
                        for (int i = codes2.Count-1; i>=0 ; i--)
			            {
                            stCode = codes2[i];
                            pos = PublicObject.arrCode2.IndexOf(stCode);

                            del = (pos + 1) * ratio21;
                            del = Math.Min(del, PublicObject.arrCode1.Count);
                            nOne += del - pos*ratio21;

                            PublicObject.arrCode1.RemoveRange(pos * ratio21, del - pos * ratio21);
                            PublicObject.arrCode2.Remove(stCode);
			            }
	                }
                    
		        }
		        else
		        {


                    nOne = PublicObject.arrCode1.Count - nMin * ratio31;
                    PublicObject.arrCode1.RemoveRange(nMin * ratio31, nOne);

                    nTwo = PublicObject.arrCode2.Count - nMin*ratio32;
                    PublicObject.arrCode2.RemoveRange(nMin * ratio32, nTwo);

                    nThree = PublicObject.arrCode3.Count - nMin;
                    PublicObject.arrCode2.RemoveRange(nMin, nThree);

		        }
	        }

	        strMsg = string.Format("未包装产品删除成功：一共删除{0}个一级码，{1}个二级码，{2}个三级码", nOne, nTwo, nThree);

	        return true;
        }

        private static bool SetRemainDelete21(ref string strMsg)
        {
            int nOne = 0, nTwo = 0;
            int ratio21 = GetCurRatios()[1];

            if (PublicObject.arrCode2.Count * ratio21 == PublicObject.arrCode1.Count)
            {
                strMsg = "无未包装产品";
                return false;
            }
            else
            {//二级码多
                int nMin = PublicObject.arrCode1.Count / ratio21;
                nMin = Math.Min(PublicObject.arrCode2.Count, nMin);

                nOne = PublicObject.arrCode1.Count - nMin * ratio21;
                PublicObject.arrCode1.RemoveRange(nMin * ratio21, nOne);

                nTwo = PublicObject.arrCode2.Count - nMin;
                PublicObject.arrCode2.RemoveRange(nMin, nTwo);
            }


            strMsg = string.Format("未包装产品删除成功：一共删除{0}个一级码，{1}个二级码", nOne, nTwo);

            return true;
        }

        public static bool QueryCodeState(string p, ref string strMsg)
        {
	        CodeInfo stCode;
            string msg = string.Empty;
            string sql;

            stCode = FindCode(p);

            if (stCode != null)
	        {
		        int pos=FindCodePos(stCode);
                int pos2 = -1;
                int ratio;

                if (stCode.stationNumber == PublicObject.CurTask.tagLevel)
                {//顶级码
                    ratio = 0;
                }
                else
                {
                    ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 1 - stCode.stationNumber];
                }
                
                if (PublicObject.bSecond)
                {
                    if (stCode.stationNumber == 2)
                    {
                        pos2 = FindCodePos2(stCode);
                    }
                    else if (stCode.stationNumber == 1)
                    {
                        pos2 = FindCodeOnePos2(stCode, ref msg);
                    }
                }

                if (pos2>=0)
                {
                    if (stCode.stationNumber == 1)
                    {
                        strMsg = string.Format("一级码对应父码已二次采集，本条码的对应二次采集序号={0}，一次采集序号={1}，父码二次采集序号={2}", pos2 + 1, pos+1, pos2/ ratio + 1);
                    }
                    else
                    {
                        strMsg = string.Format("二级码已二次采集，本条码的对应二次采集位置={0}，父码采集序号={1}", pos2 + 1, pos2 / ratio + 1);
                    }
                }
                else
                {
                    if (stCode.stationNumber == 2)
                    {
                        strMsg = string.Format("查询码状态：码已入库，{0}级码，一次序号{1}，未二次扫描，为本次生产任务，{2}",
                            stCode.stationNumber, pos + 1, p);
                    }
                    else
                    {
                        strMsg = string.Format("查询码状态：码已入库，{0}级码，一次序号{1}，为本次生产任务，{2}",
                            stCode.stationNumber, pos + 1, p);
                    }
                    
                }
                
	        }
            else
	        {
                sql = string.Format("{0} where code = {1} and taskID != {2}", EntityHelper.GetQuerySql<CodeInfo>(), p, PublicObject.CurTask.ID);
                stCode = DALOpr.QuerySingle<CodeInfo>(sql, ref strMsg);

                if (stCode == null)
	            {
		            strMsg = $"查询失败：{strMsg}，原始条码={p}";
	            }
                else
                {
                    if (JudgeCodeStateValid(stCode.codeState))
		            {
                        sql = string.Format("{0} where id = {1}", EntityHelper.GetQuerySql<ProductionTask>(),  stCode.taskID);

                        ProductionTask t = DALOpr.QuerySingle<ProductionTask>(sql, ref strMsg);
                        strMsg = string.Format("查询码状态：码已入库，{0}级码，批次{1}，入库时间{2}，{3}", 
				            stCode.stationNumber, t.batch, stCode.inTime.ToString("yyyy-MM-dd HH:mm:ss"), p);
		            }
		            else
		            {
                        
			            if(stCode.codeState==(int)code_state.CS_DISCARDED)
				            strMsg = string.Format("查询码状态：码已废弃，{0}", p);
			            else if(stCode.codeState==(int)code_state.CS_QJ)
				            strMsg = string.Format("查询码状态：码已取检，{0}", p);
			            else if(stCode.codeState==(int)code_state.CS_DEL_AUTO)
				            strMsg = string.Format("查询码状态：码已被自动剔除，{0}", p);
			            else if(stCode.codeState==(int)code_state.CS_DEL_MAN)
				            strMsg = string.Format("查询码状态：码已被手动删除，{0}", p);
			            else if(stCode.codeState==(int)code_state.CS_UNUSE)
			            {//查询历史
                            strMsg = string.Format("查询码状态：码未使用，{0}", p);
			            }
			            else 
				            strMsg = string.Format("查询码状态：码状态非法（{0}），{1}", stCode.codeState, p);
		            }
                }
	        }


	        return true;
        }

        /// <summary>
        /// 存放顺序：先旧码，再插入码
        /// </summary>
        /// <param name="saCode"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool InsertCode( List<string> saCode, ref string strMsg )
        {
	        CodeInfo codeOld, codeNew;

            if (saCode.Count != 2)
            {
                strMsg = "插入操作数量不正确，待处理数量为：" + saCode.Count;
                return false;
            }

            codeOld = FindCode(saCode[0]);

            if (codeOld != null)
	        {
		        if (!JudgeCodeStateValid(codeOld.codeState))
		        {
			        strMsg = string.Format("码插入：插入失败，旧码未入库或码为非法");
			        return false;
		        }

                if (JudgeCodeValid(saCode[1]))
                {
                    if (CheckDuplicate(saCode[1]))
                    {
                        strMsg = string.Format("码插入：插入失败，新码已入库");
                        return false;
                    }

                    codeNew = codeOld.Clone() as CodeInfo;
                    codeNew.code = saCode[1];

                    IList<CodeInfo> parr;
                    if (codeOld.stationNumber == 1)
                    {
                        parr = PublicObject.arrCode1;
                    }
                    else if (codeOld.stationNumber == 2)
                    {
                        parr = PublicObject.arrCode2;
                    }
                    else if (codeOld.stationNumber == 3)
                    {
                        parr = PublicObject.arrCode3;
                    }
                    else
                    {
                        parr = PublicObject.arrCode4;
                    }

                    if (codeOld.stationNumber == 1 && PublicObject.arrCode1.bMergeOne)
                    {
                        int idxOld = PublicObject.arrCode1.IndexOf(codeOld);
                        int line = idxOld % 2;

                        idxOld = PublicObject.arrCode1.GetList(line).IndexOf(codeOld);
                        for (int i = idxOld; i < PublicObject.arrCode1.GetList(line).Count; i++)
                        {
                            PublicObject.arrCode1.GetList(line)[i].serialNumber += 2;
                        }

                        PublicObject.arrCode1.GetList(line).Insert(idxOld, codeNew);
                    }
                    else
                    {
                        int idxOld = parr.IndexOf(codeOld);
                        for (int i = idxOld; i < parr.Count; i++)
                        {
                            parr[i].serialNumber++;
                        }

                        parr.Insert(idxOld, codeNew);

                        strMsg = string.Format("码插入：插入成功，{0}前面插入{1}", saCode[0], saCode[1]);

                    }


                    return true;

                }
                else
                {
                    strMsg = string.Format("码插入:插入失败，新码未导入，无法替换");
                    return false;
                }
	
	        }
	        else
	        {
                strMsg = string.Format("码插入：插入失败，旧码未入库：{0}", saCode[0]);
		        return false;
	        }

	        return false;
        }

        /// <summary>
        /// 方法描述：
        /// 参数描述：存放顺序：先二级码，后一级码，数量须符合按照一级二级关联比例
        /// </summary>
        public static bool InsertCode21( List<string> saCode, ref string strMsg )
        {
            int nRatio21 = GetStationRatio(2);

	        if (saCode.Count!=nRatio21+1)
	        {
		        strMsg = string.Format("码数量不正确，一个二级码须对应{0}个一级码", nRatio21);
		        return false;
	        }

	        //判断二级码是否合法
	        CodeInfo stCode2 = new CodeInfo(), stCodeTmp;
	        List<CodeInfo> arrCode = new List<CodeInfo>();

	        stCode2.code = saCode[0];

	        //if (m_dbOneLevel.QueryScanCode(stCode, ws.dwaSourceList, m_bUseTmpTable))
	        if(!CheckDuplicate(stCode2.code))
	        {
		        stCode2.sourceID = 0;
		        stCode2.subDeviceNumber = 0;
		        stCode2.serialNumber2 = 0;
		        stCode2.printTimes = 0;

		        stCode2.codeState = (int)code_state.CS_SCANED;

		        stCode2.inTime = DateTime.Now;

		        stCode2.serialNumber = GetAvailableSN(2);
		        stCode2.serialNumber2 = 0;

		        stCode2.stationNumber = 2;
		        stCode2.taskID = PublicObject.CurTask.ID;

	        } 
	        else
	        {
		        strMsg = string.Format("入库失败：二级码已扫描，不能重复入库，{0}", stCode2.code);
		        return false;
	        }


            int sn = GetAvailableSN(1); ;

	        for (int i=1; i<saCode.Count; i++)
	        {
                stCodeTmp = new CodeInfo();
                //检查所有一级码
	            stCodeTmp.sourceID = 0;
	            stCodeTmp.subDeviceNumber = 0;
	            stCodeTmp.serialNumber2 = 0;
	            stCodeTmp.printTimes = 0;
	            stCodeTmp.codeState = (int)code_state.CS_SCANED;
	            stCodeTmp.inTime = DateTime.Now;
		        stCodeTmp.code = saCode[i];

		        if(!CheckDuplicate(stCodeTmp.code))
		        {

                    stCodeTmp.serialNumber = sn + i - 1;

			        stCodeTmp.serialNumber2 = 0;

			        stCodeTmp.stationNumber = 1;
			        stCodeTmp.taskID = PublicObject.CurTask.ID;

			        arrCode.Add(stCodeTmp);
		        } 
		        else
		        {
			        strMsg = string.Format("入库失败：一级码已扫描，不能重复入库，{0}", stCodeTmp.code);
			        return false;
		        }
	        }

	        //统一插入
            AddCode(stCode2);

            foreach (var item in arrCode)
	        {
		        AddCode(item);
	        }

	        strMsg = string.Format("插入一二级码成功。操作成功。插入一二级码操作：插入成功，共插入二级码1条，一级码{0}条", arrCode.Count);

	        return true;
        }

        /// <summary>
        /// 先扫父码，再扫子码
        /// </summary>
        /// <param name="saCode"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool CheckRlt(List<string> saCode, ref string strMsg)
        {
	        CodeInfo p;

            if (saCode.Count < 2)
            {
                strMsg = "查询关联码数量不正确，待处理数量为：" + saCode.Count;
                return true;
            }

            p = FindCode(saCode[0]);

	        if (p == null)
	        {//查询是否在该批次内
		        strMsg = string.Format("查询关联：父码未入库");
		        return true;
	        }

            List<CodeInfo> arr = new List<CodeInfo>();

	        arr.Add(p);

            if (saCode.Count == 2)
            {
                p = FindCode(saCode[1]);
                if (p == null)
                {
                    strMsg = string.Format("查询关联：子码未入库");
                    return true;
                }

                arr.Add(p);

                return DoCheck(arr, ref strMsg);
            }
            else
            {//批量查询
                strMsg = "";
                for (int i = 1; i < saCode.Count; i++)
                {
                    p = FindCode(saCode[i]);
                    if (p == null)
                    {
                        if (arr.Count == 1)
                        {
                            strMsg = "查询关联：有子码未入库，列出如下：" + saCode[i];
                        }
                        else
                        {
                            strMsg += "," + saCode[i];
                        }
                    }
                    else
                    {
                        arr.Add(p);
                    }

                }

                if (arr.Count != saCode.Count)
                {
                    return true;
                }
                else
                {
                    if (arr[0].stationNumber!=2)
                    {
                        strMsg = string.Format("查询关联：批量查询关联只支持一二级查询，父码不是二级码");
                        return true;
                    }
                    for (int i = 1; i < arr.Count; i++)
                    {
                        if (arr[i].stationNumber!=1)
                        {
                            strMsg = string.Format("查询关联：批量查询关联只支持一二级查询，子码不是一级码");
                            return true;
                        }
                    }

                    return DoCheck21Batch(arr, ref strMsg);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="codeP">父码</param>
        /// <param name="codeS">子码</param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool CheckRlt(string codeP, string codeS, ref string strMsg)
        {
            CodeInfo p;

            p = FindCode(codeP);

            if (p == null)
            {//查询是否在该批次内
                strMsg = string.Format("查询关联：父码未入库");
                return true;
            }

            List<CodeInfo> arr = new List<CodeInfo>();

            arr.Add(p);

            p = FindCode(codeS);
            if (p == null)
            {
                strMsg = string.Format("查询关联：子码未入库");
                return true;
            }

            arr.Add(p);

            return DoCheck(arr, ref strMsg);
        }

        private static bool DoCheck(List<CodeInfo> arr, ref string strMsg)
        {
            //不跨级，直接根据贴码比例判断

            //跨级：中间码可能二次扫描，先实现：12级查询、13级查询、23级查询
	        CodeInfo p = arr[0];
	        CodeInfo son = arr[1];

	        int nDiff = p.stationNumber-son.stationNumber;
	        if (nDiff<0)
	        {
		        strMsg = ("关联查询：子码与父码关系颠倒");
		        return true;
	        }
	        else if(nDiff==0)
	        {
		        strMsg = ("关联查询：父码与子码为同一级码");
		        return true;
	        }
	        else
	        {

		        if (p.stationNumber==2 && son.stationNumber==1)
		        {
			        return DoCheck21(arr, ref strMsg);
		        }
		        else if (p.stationNumber==3 && son.stationNumber==2)
		        {
			        return DoCheck32(arr, ref strMsg);
		        } 
		        else if(p.stationNumber==3 && son.stationNumber==1)
		        {
			        return DoCheck31(arr, ref strMsg);
		        }
                else if (p.stationNumber == 4 && son.stationNumber == 3)
                {
                    return DoCheck43(arr, ref strMsg);
                }
                else if (p.stationNumber == 4 && son.stationNumber == 2)
                {
                    return DoCheck42(arr, ref strMsg);
                }
		        else
		        {
			        strMsg = string.Format("关联查询：关联层次不正确，父码级别{0}，子码级别{1}", p.stationNumber, son.stationNumber);
		        }
	        }

	        return true;
        }

        private static bool DoCheck42(List<CodeInfo> arr, ref string strMsg)
        {
            int snP = 1 + PublicObject.arrCode4.IndexOf(arr[0]);
            int snSon = 1 + PublicObject.arrCode2.IndexOf(arr[1]);
            int snSecond;

            int ratio32 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 3];
            int ratio43 = GetCurLevelRatios()[0];
            int ratio42 = ratio43 * ratio32;

            if (PublicObject.bSecond)
            {//二次扫描

                snSecond = FindCodePos2(arr[1]);

                if (snSecond >= 0)
                {
                    snSecond++;

                    if (snSecond <= snP * ratio42 && snSecond > (snP - 1) * ratio42)
                    {
                        strMsg = string.Format("查询关联：关联成功，二级序号{3}，二次扫描序号{0}，四级序号{1}，包装内二级码序号{2}",
                            snSecond, snP, ((snSecond - 1) % ratio42) + 1, snSon);
                        return true;

                    }

                    else
                        strMsg = string.Format("查询关联：关联失败，二级序号{3}，二次扫描序号{0}，四级序号{1}，二级码属于四级序号{2}", snSecond, snP, ((snSecond - 1) / ratio42) + 1, snSon);
                }
                else
                {
                    strMsg = string.Format("查询关联：关联失败，二级码未二次扫描，二级序号{1}，四级序号{0}", snP, snSon);
                }


            }
            else
            {
                if (snSon <= snP * ratio42 && snSon > (snP - 1) * ratio42)
                {
                    strMsg = string.Format("查询关联：关联成功，二级总序号{0}，四级序号{1}，包装内二级码序号{2}",
                        ((snSon - 1) % ratio42) + 1, snP, snSon, snP, ((snSon - 1) % ratio42) + 1);
                }
                else
                {
                    strMsg = string.Format("查询关联：关联失败，二级总序号{0}，四级序号{1}，二级码属于四级序号{2}", snSon, snP, (snSon - 1) / ratio42 + 1);
                }
            }



            return true;
        }

        private static bool DoCheck31(List<CodeInfo> arr, ref string strMsg)
        {
            int snP = 1 + PublicObject.arrCode3.IndexOf(arr[0]);
            int snSon = 1 + PublicObject.arrCode1.IndexOf(arr[1]);
            int snSecond, snFirst;

            int ratio32 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 3];
            int ratio21 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
            int ratio31 = ratio21 * ratio32;

            if (PublicObject.bSecond)
            {//二次扫描
                for (int i = 0; i < PublicObject.arrCode2.Count; i++)
                {
                    snSecond = FindCodePos2(PublicObject.arrCode2[i]);
                    if (snSecond <= snP * ratio32 && snSecond > (snP - 1) * ratio32)
                    {
                        snFirst = i + 1;//二级码的一次扫描序号

                        if (snSon <= snFirst * ratio21 && snSon > (snFirst - 1) * ratio21)
                        {
                            strMsg = string.Format("查询关联：关联成功，一级总序号{0}，二级序号{1}，二级二次扫描序号{4}，三级序号{2}，二级包装内一级码序号{3}", snSon, snFirst, snP, ((snSon - 1) % ratio21) + 1, snSecond);

                            return true;
                        }
                    }
                }

                strMsg = string.Format("查询关联：一三级关联失败，一级总序号{0}，三级序号{1}，一级码属于三级序号{2}", snSon, snP, FindCodeOnePos2(arr[1], ref strMsg) / ratio31 + 1);
            }
            else
            {
                if (snSon <= snP * ratio31 && snSon > (snP - 1) * ratio31)
                {
                    strMsg = string.Format("查询关联：关联成功，一级总序号{0}，三级序号{1}，包装内一级码序号{2}",
                       snSon, snP, ((snSon - 1) % ratio31) + 1);
                }
                else
                {
                    strMsg = string.Format("查询关联：一三级关联失败，一级总序号{0}，三级序号{1}，一级码属于三级序号{2}", snSon, snP, (snSon - 1) / ratio31 + 1);
                }
            }



            return true;
        }

        private static bool DoCheck32(List<CodeInfo> arr, ref string strMsg)
        {

            int snP = 1 + PublicObject.arrCode3.IndexOf(arr[0]);
            int snSon = 1 + PublicObject.arrCode2.IndexOf(arr[1]);
            int snSecond;

            int ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 3];

            if (PublicObject.bSecond)
            {//二次扫描

                snSecond = FindCodePos2(arr[1]);

                if (snSecond >= 0)
                {
                    snSecond++;

                    if (snSecond <= snP * ratio && snSecond > (snP - 1) * ratio)
                    {
                        strMsg = string.Format("查询关联：关联成功，二级码一次扫描序号{3}，二次扫描序号{0}，三级序号{1}，包装内二级码序号{2}",
                            snSecond, snP, ((snSecond - 1) % ratio) + 1, snSon);
                        return true;

                    }
                    else
                        strMsg = string.Format("查询关联：关联失败，二级码一次扫描序号{3}，二次扫描序号{0}，三级序号{1}，二级码属于三级序号{2}", snSecond, snP, ((snSecond - 1) / ratio) + 1, snSon);
                }
                else
                {
                    strMsg = string.Format("查询关联：关联失败，二级码未二次扫描，二级码一次扫描序号{1}，三级序号{0}", snP, snSon);
                }


            }
            else
            {
                if (snSon <= snP * ratio && snSon > (snP - 1) * ratio)
                {
                    strMsg = string.Format("查询关联：关联成功，二级总序号{0}，三级序号{1}，包装内二级码序号{2}", snSon, snP, ((snSon - 1) % ratio) + 1);
                }
                else
                {
                    strMsg = string.Format("查询关联：二三级关联失败，二级总序号{0}，三级序号{1}，二级码属于三级序号{2}", snSon, snP, (snSon - 1) / ratio + 1);
                }
            }



            return true;
        }

        private static bool DoCheck43(List<CodeInfo> arr, ref string strMsg)
        {
            int ratio43 = GetCurLevelRatios()[0];


            int snP = 1 + PublicObject.arrCode4.IndexOf(arr[0]);
            int snSon = 1 + PublicObject.arrCode3.IndexOf(arr[1]);

            if (snSon <= snP * ratio43 && snSon > (snP - 1) * ratio43)
            {
                strMsg = string.Format("查询关联：关联成功，三级总序号{0}，四级序号{1}，包装内三级码序号{2}",
                    snSon, snP, ((snSon - 1) % ratio43) + 1);
            }
            else
            {
                strMsg = string.Format("查询关联：三四级关联失败，三级总序号{0}，四级序号{1}，三级码属于四级序号{2}", snSon, snP, (snSon - 1) / ratio43 + 1);
            }

            return true;
        }

        private static bool DoCheck21(List<CodeInfo> arr, ref string strMsg)
        {          
            int snP = 1 + PublicObject.arrCode2.IndexOf(arr[0]);
            int snSon = 1 + PublicObject.arrCode1.IndexOf(arr[1]);
            int ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel-2];

            if (snSon <= snP * ratio && snSon > (snP - 1) * ratio)
            {
                strMsg = string.Format("查询关联：关联成功，一级总序号{0}，二级序号{1}，包装内一级码序号{2},二级二次扫描序号{3}",
                    snSon, snP, ((snSon - 1) % ratio) + 1, FindCodePos2(arr[0]) + 1);
            }
            else
            {
                strMsg = string.Format("查询关联：一二级关联失败，一级总序号{0}，二级序号{1}，二级二次扫描序号{3}，一级码属于二级序号{2}，一级码属于二级二次扫描序号{4}", 
                    snSon, snP, (snSon-1)/ratio + 1, FindCodePos2(arr[0])+1, FindCodeOnePos2(arr[1], ref strMsg) / ratio + 1);
            }

            return true;
        }

        private static bool DoCheck21Batch(List<CodeInfo> arr, ref string strMsg)
        {
            int snP = 1 + PublicObject.arrCode2.IndexOf(arr[0]);
            int ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
            List<int> snSons = new List<int>();
            int nNG = 0;
            string sTmp = "";

            strMsg = $"查询关联：二级序号{snP}，一级码包装内序号分别是：";

            for (int i = 1; i < arr.Count; i++)
            {
                int snSon = 1 + PublicObject.arrCode1.IndexOf(arr[i]);

                if (snSon <= snP * ratio && snSon > (snP - 1) * ratio)
                {
                    strMsg += $"OK-{((snSon - 1) % ratio) + 1}，";
                }
                else
                {
                    strMsg += $"NG-一级总序号{snSon}  二级二次扫描序号{FindCodePos2(arr[0]) + 1}  一级码属于二级序号{(snSon - 1) / ratio + 1}  一级码属于二级二次扫描序号{FindCodeOnePos2(arr[i], ref sTmp) / ratio + 1}，";
                    nNG++;
                    //strMsg = string.Format("查询关联：一二级关联失败，一级总序号{0}，二级序号{1}，二级二次扫描序号{3}，一级码属于二级序号{2}，一级码属于二级二次扫描序号{4}",
                    //    snSon, snP, (snSon - 1) / ratio + 1, FindCodePos2(arr[0]) + 1, FindCodeOnePos2(arr[1], ref strMsg) / ratio + 1);
                }
            }

            if (nNG>0)
            {
                strMsg += "关联失败";
            }
            else
            {
                strMsg += "关联成功";
            }

            return true;
        }

        public static bool ReplaceCode( List<string> saCode, ref string strMsg )
        {
	        CodeInfo codeOld;

            if (saCode.Count != 2)
            {
                strMsg = "互换码数量不正确，待处理数量为：" + saCode.Count;
                return false;
            }

            codeOld = FindCode(saCode[0]);

	        if (codeOld!=null)
	        {
		        if (!JudgeCodeStateValid(codeOld.codeState))
		        {
			        strMsg = string.Format("码替换：替换失败，码状态不正确，状态={0}", codeOld.codeState);
			        return false;
		        }

                if (JudgeCodeValid(saCode[1]))
		        {
                    if (CheckDuplicate(saCode[1]))
			        {
				        strMsg = string.Format("码替换：替换失败，新码已入库");
				        return false;
			        }

                    codeOld.code = saCode[1];
                    //PublicObject.CodeScanned.Remove(saCode[0]);
                    //PublicObject.CodeScanned.Add(saCode[1]);

			        strMsg = string.Format("码替换：替换成功，{0}被替换为{1}", saCode[0], saCode[1]);

		        }
		        else
		        {
			        strMsg = string.Format("新旧替换失败：新码未导入，无法替换");
                    return false;
		        }
	        }
	        else
	        {
		        strMsg = string.Format("码替换：替换失败，旧码未入库：{0}", saCode[0]);
		        return false;
	        }

	        return true;
        }

        public static bool SwitchCode( List<string> saCode, ref string strMsg )
        {
            if (saCode.Count != 2)
            {
                strMsg = "互换码数量不正确，待处理数量为：" + saCode.Count;
                return false;
            }

	        CodeInfo c1, c2;

            c1 = FindCode(saCode[0]);
            c2 = FindCode(saCode[1]);
	        if (c1 != null && c2 != null)
	        {
		        if (JudgeCodeStateValid(c1.codeState) && JudgeCodeStateValid(c2.codeState))
		        {
			        string tmp;

			        tmp = c1.code;
			        c1.code = c2.code;
			        c2.code = tmp;

			        			        
			        strMsg = string.Format("码互换成功：码1={0}，码2={1}", c2.code, c1.code);
		        }
		        else
		        {
			        strMsg = string.Format("两码互换：互换失败，码未入库或码为非法");
			        return false;
		        }
	        }
	        else
	        {
                strMsg = string.Format("两码互换：互换失败，码未入库");
		        return false;
	        }

	        return true;
        }

        public static bool DeleteInBatch( List<string> saCode, ref string strMsg )
        {
	        CodeInfo stCode;
	        int nLoss=0, nCant=0;

	        for (int i=0; i<saCode.Count; i++)
	        {
                stCode = FindCode(saCode[i]);
		        if (stCode != null)
		        {
			        if(!JudgeCodeStateValid(stCode.codeState))
			        {
				        nCant++;
                        
			        }
			        else
			        {//只允许删除已扫描数据
                        DeleteCode(stCode);
			        }
		        }
		        else
			        nLoss++;
	        }

	        //同步更新关联码

	        if(nLoss==0 && nCant==0)
		        strMsg = string.Format("批量删除：成功删除{0}条数据", saCode.Count);
	        else
		        strMsg = string.Format("批量删除：成功删除{0}条数据，有{1}条未找到，有{2}条不能删除", saCode.Count-nLoss-nCant, nLoss, nCant);

	        return true;
        }

        private static bool DeleteSec(string code, ref string strMsg)
        {
            CodeInfo stCode;
            string reason = string.Empty;
            bool bRes;
            stCode = FindCode(code);

            if (stCode != null)
            {
                if (JudgeCodeStateValid(stCode.codeState))
                {//取检或者废弃的不允许删除
                    if (stCode.serialNumber2 > 0)
                    {
                        stCode.serialNumber2 = 0;
                        bRes = true;

                    }
                    else
                    {
                        strMsg = string.Format("删除失败：码尚未二次扫描，无法删除");
                        return false;
                    }
                }
                else
                {
                    strMsg = string.Format("删除失败：码状态错误[{0}]，无法删除", stCode.codeState);
                    return false;
                }
            }
            else
            {
                strMsg = string.Format("删除失败：无法找到该码[{0}]，无法删除", code);
                return false;
            }

            if (!bRes)
            {
                strMsg = "删除失败：" + reason;
            }

            return bRes;
        }

        public static bool DeletePackage( string code, ref string strMsg )
        {
	        CodeInfo stCode;
	        string strTmp;
            string reason = string.Empty;
            bool bRes;
		    stCode = FindCode(code);

		    if (stCode != null)
		    {
			    if(JudgeCodeStateValid(stCode.codeState))
			    {//取检或者废弃的不允许删除
				    if (stCode.stationNumber==2)
				    {
                        bRes = DeletePackage21(stCode, ref reason);

				    }
				    else if(stCode.stationNumber==3)
				    {
					    bRes = DeletePackage31(stCode, ref reason);
	
				    }
                    else if (stCode.stationNumber == 4)
                    {
                        bRes = DeletePackage41(stCode, ref reason);
                    }
                    else
                    {
                        DeleteCode(stCode);
                        bRes = true;
                    }
			    }
			    else
			    {
				    strMsg = string.Format("删除失败：码状态错误[{0}]，无法删除", stCode.codeState);
                    return false;
			    }
		    }
		    else
			{
                strMsg = string.Format("删除失败：无法找到该码[{0}]，无法删除", code);
                return false;
            }

	        if (!bRes)
	        {
		        strMsg = "删除失败：" + reason;
	        }

	        return bRes;
        }

        public static bool PickTopPackage21(ref string strMsg)
        {
            IList<CodeInfo> parr = PublicObject.arrCode2;
            int ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
            

            int nBase = (parr.Count) * ratio;//被删除的一级码起始位置

            if (nBase + ratio > PublicObject.arrCode1.Count)
            {
                Console.Write("删除整包装失败：不满整包装\n");
                strMsg = "删除整包装失败：不满整包装";
                return false;
            }

            for (int i = nBase + ratio - 1; i >= nBase; i--)
            {
                DeleteCode(PublicObject.arrCode1[i]);
            }

            return true;
        }


        public static bool  DeletePackage21( CodeInfo topCode, ref string strMsg )
        {
            CodeInfo stCode;
            int snP = PublicObject.arrCode2.IndexOf(topCode);
            int ratio = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];

            int nBase = snP * ratio;//被删除的一级码起始位置

	        if (nBase + ratio > PublicObject.arrCode1.Count)
	        {
		        Console.Write("删除整包装失败：不满整包装\n");
                strMsg = "不满整包装";
		        return false;
	        }

            for (int i = nBase + ratio - 1; i>=nBase; i--)
            {
                stCode = PublicObject.arrCode1[i];
                DeleteCode(stCode);
            }

            //删除二级码
            DeleteCode(topCode);

	        return true;
        }

        public static bool  DeletePackage31( CodeInfo topCode, ref string strMsg )
        {

	        int snP = PublicObject.arrCode3.IndexOf(topCode);

            int ratio32 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 3];
            int ratio21 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
            int ratio31 = ratio21 * ratio32;

	        int nBase;//被删除的二级码起始位置

	        CodeInfo stCode;

	        nBase = snP*ratio32;

	        if (nBase + ratio32>PublicObject.arrCode2.Count || (nBase+ ratio32)*ratio21>PublicObject.arrCode1.Count)
	        {
		        Console.Write("删除整包装失败：不满整包装\n");
                strMsg = "不满整包装";
		        return false;
	        }

	        if (PublicObject.bSecond)
	        {//二次扫描
		        List<CodeInfo> arrCodeDel;

		        arrCodeDel = FindArrayByPos2(nBase, ratio32);

		        if(arrCodeDel.Count!=ratio32)
		        {
			        Console.Write("删除整包装失败：二级码找到{0}，实际三级二级比值：{1}\n", arrCodeDel.Count, ratio32);
                    strMsg = string.Format("二级码找到{0}，实际三级二级比值：{1}", arrCodeDel.Count, ratio32);
			        return false;
		        }

		        for (int i=arrCodeDel.Count-1; i>=0; i--)
		        {
			        stCode = arrCodeDel[i];
			        DeletePackage21(stCode, ref strMsg);
		        }

	        }
	        else
	        {
		        for (int i=nBase+ratio32-1; i>=nBase; i--)
		        {
			        stCode = PublicObject.arrCode2[i];
			        DeletePackage21(stCode, ref strMsg);
		        }
	        }

	        //删除三级码
            DeleteCode(topCode);
	        return true;
        }

        public static bool DeletePackage41(CodeInfo topCode, ref string strMsg)
        {
            int[] dwa = GetCurRatios();

            int snP = PublicObject.arrCode4.IndexOf(topCode);
            int ratio43 = dwa[1];
            int ratio42 = dwa[2];
            int ratio41 = dwa[3];
            int ratio21 = ratio41/ratio42;
            int ratio32 = ratio42 / ratio43;
            int ratio31 = ratio41 / ratio43;
            int nBase;//被删除的三级码起始位置

            CodeInfo stCode;

            nBase = snP * ratio43;

            if ((nBase + ratio43) * ratio32 > PublicObject.arrCode2.Count || (nBase + ratio43) * ratio31 > PublicObject.arrCode1.Count || (snP + 1) * ratio43 > PublicObject.arrCode3.Count)
            {
                Console.Write("删除整包装失败：不满整包装\n");
                strMsg = "不满整包装";
                return false;
            }
     
            for (int i = nBase + ratio43 - 1; i >= nBase; i--)
            {
                stCode = PublicObject.arrCode3[i];

                DeletePackage31(stCode, ref strMsg);
            }

            //删除四级码
            DeleteCode(topCode);
            
            return true;
        }

        
        /// <summary>
        /// [2016-5-22 ASUS]
        /// 方法描述：手工采集，放置最后，一般用于不能自动采集但是需要散装的产品
        /// 参数描述：nStation是码级别
        /// </summary>
        public static bool AppendCode(List<string> saCode, int nStation, ref string strMsg)
        {
	        CodeInfo stCodeTmp = new CodeInfo();
	        List<CodeInfo> arrCode = new List<CodeInfo>();
	        DateTime tm = DateTime.Now;
            IList<CodeInfo> parr;
	        //检查所有码
	        stCodeTmp.sourceID = 0;
	        stCodeTmp.subDeviceNumber = 0;
	        stCodeTmp.serialNumber2 = 0;
	        stCodeTmp.printTimes = 0;
	        stCodeTmp.codeState = (int)code_state.CS_SCANED;


	        stCodeTmp.inTime = tm;
	        if (nStation==1)
	        {
		        parr = PublicObject.arrCode1;
	        } 
	        else if(nStation==2)
	        {
                parr = PublicObject.arrCode2;
	        }
	        else if(nStation==3)
	        {
                parr = PublicObject.arrCode3;
	        }
	        else
	        {
                parr = PublicObject.arrCode4;
	        }


	        for (int i=0; i<saCode.Count; i++)
	        {
		        stCodeTmp.code = saCode[i];

		        if(!CheckDuplicate(stCodeTmp.code))
		        {

                    stCodeTmp.serialNumber = GetAvailableSN(nStation);

			        stCodeTmp.serialNumber2 = 0;

			        stCodeTmp.stationNumber = nStation;
			        stCodeTmp.taskID = PublicObject.CurTask.ID;

			        arrCode.Add(stCodeTmp);
		        } 
		        else
		        {
			        strMsg = string.Format("入库失败：码已扫描，不能重复入库，{0}", stCodeTmp.code);
			        return false;
		        }
	        }

	        //统一插入
            foreach (var item in arrCode)
            {
                AddCode(item);
            }

	        strMsg = string.Format("附加{0}级尾数操作：附加成功，共插入条码{1}条", nStation, arrCode.Count);

	        return true;
        }

        /// <summary>
        /// 范围删除码
        /// </summary>
        /// <param name="station">码级别</param>
        /// <param name="st">起始索引</param>
        /// <param name="ed">结束索引</param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool DeleteRange(int station, int st, int ed, ref string strMsg)
        {
            try
            {
                switch (station)
                {
                    case 4:
                        if (ed>=PublicObject.arrCode4.Count)
                        {
                            strMsg = "删除索引超出四级码数量";
                            return false;
                        }
                        PublicObject.arrCode4.RemoveRange(st, ed - st + 1);
                        break;
                    case 3:
                        if (ed >= PublicObject.arrCode3.Count)
                        {
                            strMsg = "删除索引超出三级码数量";
                            return false;
                        }
                        PublicObject.arrCode3.RemoveRange(st, ed - st + 1);
                        break;
                    case 2:
                        if (ed >= PublicObject.arrCode2.Count)
                        {
                            strMsg = "删除索引超出二级码数量";
                            return false;
                        }
                        return DeleteRange2(st, ed, ref strMsg);
                    case 1:
                        if (ed >= PublicObject.arrCode1.Count)
                        {
                            strMsg = "删除索引超出一级码数量";
                            return false;
                        }
                        return DeleteRange1(st, ed, ref strMsg);
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                strMsg = ex.Message;
                return false;
            }

            return true;
        }

        /// <summary>
        /// 范围删除一级码
        /// </summary>
        /// <param name="st">起始索引</param>
        /// <param name="ed">结束索引</param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool DeleteRange1(int st, int ed, ref string strMsg)
        {
            if (PublicObject.bSecond)
            {
                //int ratio21 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
                //for (int i = ed; i >= st; i--)
                //{
                //    int sn2 = i / ratio21;//对应二级码的二次扫描序号
                //    int ys = i % ratio21;//二级包装内一级码索引
                //    CodeInfo ci = FindCodeByPos2(sn2);
                //    int toDel = FindCodePos(ci) * ratio21 + ys;
                //    PublicObject.arrCode1.RemoveAt(toDel);
                //}

                //统一都按照一次采集删除
                for (int i = ed; i >= st; i--)
                {
                    PublicObject.arrCode1.RemoveAt(i);
                }
            }
            else
            {
                for (int i = ed; i >= st; i--)
                {
                    PublicObject.arrCode1.RemoveAt(i);
                }
            }
            return true;
        }

        /// <summary>
        /// 范围删除二级码
        /// </summary>
        /// <param name="st">起始索引</param>
        /// <param name="ed">结束索引</param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static bool DeleteRange2(int st, int ed, ref string strMsg)
        {
            if (PublicObject.bSecond)
            {//二次扫描
                List<CodeInfo> codes2 = PublicObject.arrCode2.FindAll(c => c.serialNumber2 > 0).OrderBy(c => c.serialNumber2).ToList();

                for (int i = st; i <= ed; i++)
                {
                    PublicObject.arrCode2.Remove(codes2[i]);
                }
            }
            else
            {
                PublicObject.arrCode2.RemoveRange(st, ed - st + 1);
            }
            return true;
        }

        #endregion



        #region 其他辅助

        public static void AddUniScanner(LineDevice dev)
        {
            UniScanner us = new UniScanner();

            if (dev.deviceType == (int)in_device_type.IDT_FUNC_SCANNER)
                us.SetDev(dev, false);
            else
                us.SetDev(dev, true);

            m_arrUniScanner.Add(us);
        }

        public static void ClearUniScanner()
        {
            m_arrUniScanner.Clear();
        }


        /// <summary>
        /// 根据一次扫描序号查找码信息
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static CodeInfo FindCode(string code)
        {
            for (int i = 0; i < PublicObject.arrCode1.Count; i++)
            {
                if (PublicObject.arrCode1[i].code.Equals(code))
                {
                    return PublicObject.arrCode1[i];
                }
            }


            for (int i = 0; i < PublicObject.arrCode2.Count; i++)
            {
                if (PublicObject.arrCode2[i].code.Equals(code))
                {
                    return PublicObject.arrCode2[i];
                }
            }

            for (int i = 0; i < PublicObject.arrCode3.Count; i++)
            {
                if (PublicObject.arrCode3[i].code.Equals(code))
                {
                    return PublicObject.arrCode3[i];
                }
            }

            for (int i = 0; i < PublicObject.arrCode4.Count; i++)
            {
                if (PublicObject.arrCode4[i].code.Equals(code))
                {
                    return PublicObject.arrCode4[i];
                }
            }

            return null;
        }

        public static void DeleteCode(CodeInfo code)
        {
            switch (code.stationNumber)
            {
                case 1:
                    PublicObject.arrCode1.Remove(code); break;
                case 2:
                    PublicObject.arrCode2.Remove(code); break;
                case 3:
                    PublicObject.arrCode3.Remove(code); break;
                case 4:
                    PublicObject.arrCode4.Remove(code); break;
                default:
                    break;
            }

            //PublicObject.CodeScanned.Remove(code.code);
        }

        public static void AddCode(CodeInfo code)
        {
            switch (code.stationNumber)
            {
                case 1:
                    if (PublicObject.arrCode1.bMergeOne)
                    {
                        PublicObject.arrCode1.Add(code.serialNumber%2, code); break;
                    }
                    else
                    {
                        PublicObject.arrCode1.Add(code); break;
                    }
                    
                case 2:
                    PublicObject.arrCode2.Add(code); break;
                case 3:
                    PublicObject.arrCode3.Add(code); break;
                case 4:
                    PublicObject.arrCode4.Add(code); break;
                default:
                    break;
            }

            //PublicObject.CodeScanned.Add(code.code);
        }

        //public static int FindCodeIndex(string code, int stationNumber)
        //{

        //}
        public static bool JudgeCodeStateValid(int nCS)
        {
            if (nCS == (int)code_state.CS_IMP)
            {
                return true;
            }
            else if (nCS == (int)code_state.CS_SCANED)
            {
                return true;
            }
            else if (nCS == (int)code_state.CS_PRINTED)
            {
                return true;
            }

            return false;
        }

        public static bool JudgeCodeStateUsefull(int nCS)
        {
            if (nCS == (int)code_state.CS_DEL_AUTO)
            {
                return true;
            }
            else if (nCS == (int)code_state.CS_DEL_MAN)
            {
                return true;
            }
            else if (nCS == (int)code_state.CS_UNUSE)
            {
                return true;
            }

            return false;
        }

        public static bool JudgeCodeValid(string code)
        {
            //return PublicObject.CodeValid.Contains(code);
            if (PublicObject.CodeValid.Count > 0)
            {//2021-02-16
                foreach (var item in PublicObject.CodeValid)
                {
                    if (item.Contains(code))
                    {
                        return true;
                    }
                }

                return false;
            }
            else
            {
                return true;
            }
            
        }

        public static bool CheckDuplicate( string code )
        {
	        CodeInfo c;

            if (!DUP_CHECK)
            {
                return false;
            }

            c = FindCode(code);

	        if( c!=null)
	        {
		        if (JudgeCodeStateUsefull(c.codeState))
		        {
			        return false;
		        } 
		        else
		        {
			        return true;
		        }
	        }
	        else
            {
                
                if (PublicObject.CodeScanned.Contains(code))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 获取顶级包装对应各级包装层次的比例:ratio44,ratio43,ratio42,ratio41
        /// 比如1:20，则返回 1和20
        /// 1:2:4:40，则返回1/2/4/40
        /// </summary>
        /// <returns></returns>
        public static int[] GetCurRatios()
        {
            string ratio = PublicObject.CurTask.tagRatio;
            return AppHelper.GetRatios(ratio);
        }

        /// <summary>
        /// 四级关联的各级包装数量顺序ratio43,ratio32,ratio21,0
        /// 三级关联的各级包装数量顺序ratio32,ratio21,0
        /// 二级关联的各级包装数量顺序ratio21,0
        /// </summary>
        /// <returns></returns>
        public static int[] GetCurLevelRatios()
        {
            string ratio = PublicObject.CurTask.tagRatio;
            return AppHelper.GetLevelRatios(ratio);
        }

        /// <summary>
        ///  获取各工位一级码比例:ratio41, ratio31, ration21
        /// </summary>
        /// <param name="stationNum">工位号</param>
        /// <returns></returns>
        public static int GetStationRatio(int stationNum)
        {
            string ratio = PublicObject.CurTask.tagRatio;
            return AppHelper.GetStationRatio(stationNum, ratio);
        }

        /// <summary>
        ///  获取各工位码数量
        /// </summary>
        /// <param name="stationNum">工位号</param>
        /// <returns></returns>
        public static int GetStationCodeQty(int stationNum)
        {
            switch (stationNum)
            {
                case 1:
                    return PublicObject.arrCode1.Count;
                case 2:
                    return PublicObject.arrCode2.Count;
                case 3:
                    return PublicObject.arrCode3.Count;
                case 4:
                    return PublicObject.arrCode4.Count;
                default:
                    return 0;
            }
        }

        /// <summary>
        /// 根据二次扫描位置查找码集合， pos1 ≤ 二次扫描位置 ＜ pos1 + cnt
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="cnt"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos2( int pos1, int cnt)
        {
            List<CodeInfo> orderCodes = PublicObject.arrCode2.FindAll(c => c.serialNumber2 > 0).OrderBy(c => c.serialNumber2).ToList();

            return orderCodes.Skip(pos1).Take(cnt).ToList();

        }

        /// <summary>
        /// 根据一次扫描位置查找码集合， pos1 ≤ 一次扫描位置 ＜ pos1 + cnt
        /// </summary>
        /// <param name="pos1"></param>
        /// <param name="cnt"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos1(int station, int pos1, int cnt)
        {
            switch (station)
            {
                case 1:
                        return PublicObject.arrCode1.FindRange(pos1, cnt).ToList();
                case 2:
                    return PublicObject.arrCode2.Skip(pos1).Take(cnt).ToList();
                case 3:
                    return PublicObject.arrCode3.Skip(pos1).Take(cnt).ToList();
                case 4:
                    return PublicObject.arrCode4.Skip(pos1).Take(cnt).ToList();
                default:
                    return null;
            }

        }

        /// <summary>
        /// 根据二次扫描位置查找码集合， pos1 ≤ 二次扫描位置 ＜ tail
        /// </summary>
        /// <param name="pos1"></param>
        /// <returns></returns>
        public static List<CodeInfo> FindArrayByPos2(int pos1)
        {
            return FindArrayByPos2(pos1, PublicObject.arrCode2.Count - pos1);
        }

        /// <summary>
        /// 根据二次扫描序号查找位置，位置从0开始
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodePos2( CodeInfo stCode)
        {
            if (stCode.serialNumber2<=0)
            {//未二次扫描
                return -1;
            }
	        //根据二次扫描序号对二级码重新排序
            List<CodeInfo> codes = PublicObject.arrCode2.FindAll(c=>c.serialNumber2>0).OrderBy(c=>c.serialNumber2).ToList();
            return codes.IndexOf(stCode);
        }

        /// <summary>
        /// 获取一级码的包装位置，从0开始。。如果不是二次采集，则包装位置和码位置一致，否则包装位置 = 父码的二次序号 X ratio21 + 码位置 % ratio21
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodeOnePos2(CodeInfo stCode, ref string msg)
        {
            if (stCode.stationNumber != 1)
            {
                msg = "FindCodeOnePos2只适用于一级码";
                return -1;
            }

            if (PublicObject.bSecond)
            {
                CodeInfo cp = GetParent(stCode, ref msg);

                if (cp == null)
                {
                    return -1;
                }

                int ratio21 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];

                return FindCodePos2(cp) * ratio21 + FindCodePos(stCode) % ratio21;
            }
            else
            {
                return FindCodePos(stCode);
            }
        }

        /// <summary>
        /// 根据一次扫描序号查找位置，位置从0开始
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static int FindCodePos(CodeInfo stCode)
        {
            IList<CodeInfo> parr;

            switch (stCode.stationNumber)
            {
                case 1:
                    parr = PublicObject.arrCode1;break;
                case 2:
                    parr = PublicObject.arrCode2; break;
                case 3:
                    parr = PublicObject.arrCode3; break;
                case 4:
                    parr = PublicObject.arrCode4; break;
                default:
                    return -1;
            }

            if (stCode.stationNumber == 1 && PublicObject.arrCode1.bMergeOne)
            {
                return PublicObject.arrCode1.IndexOf(stCode);
            }
            else
            {
                return parr.IndexOf(stCode);
            }
            
        }

        /// <summary>
        /// 获取条码
        /// </summary>
        /// <param name="stCode"></param>
        /// <returns></returns>
        public static CodeInfo GetCode(int station, int idx)
        {
            IList<CodeInfo> parr = PublicObject.arrCode1;

            switch (station)
            {
                case 1:
                    parr = PublicObject.arrCode1; break;
                case 2:
                    parr = PublicObject.arrCode2; break;
                case 3:
                    parr = PublicObject.arrCode3; break;
                case 4:
                    parr = PublicObject.arrCode4; break;
            }

            if (station == 1 && PublicObject.arrCode1.bMergeOne)
            {
                if (idx >= 0 && idx < PublicObject.arrCode1.Count)
                {
                    return PublicObject.arrCode1[idx];
                }
                else
                {
                    return null;
                }
            }
            else
            {
                if (idx >= 0 && idx < parr.Count)
                {
                    return parr[idx];
                }
                else
                {
                    return null;
                }
            }
 
        }


        static CodeInfo FindCodeByPos2(int snPos)
        {
            //根据二次扫描序号对二级码重新排序
            List<CodeInfo> codes = PublicObject.arrCode2.FindAll(c => c.serialNumber2 > 0).OrderBy(c=>c.serialNumber2).ToList();

            return codes[snPos];
        }


        public static int GetAvailableSN(int stationNum)
        {
            IList<CodeInfo> parr;
            switch (stationNum)
            {
                case 1:
                    parr = PublicObject.arrCode1;break;
                case 2:
                    parr = PublicObject.arrCode2; break;
                case 3:
                    parr = PublicObject.arrCode3; break;
                case 4:
                    parr = PublicObject.arrCode4; break;
                default:
                    parr = PublicObject.arrCode1;break;;
            }

            if (parr.Count == 0)
            {
                return 1;
            }
            else
                return parr.Max(u => u.serialNumber) + 1;
        }

        public static int GetPrintSN(int stationNum)
        {
            IList<CodeInfo> parr;
            switch (stationNum)
            {
                case 1:
                    parr = PublicObject.arrCode1; break;
                case 2:
                    parr = PublicObject.arrCode2; break;
                case 3:
                    parr = PublicObject.arrCode3; break;
                case 4:
                    parr = PublicObject.arrCode4; break;
                default:
                    parr = PublicObject.arrCode1; break; ;
            }

            return parr.Count + 1;

            // return GetAvailableSN(stationNum);
        }

        private static int GetAvailableSN2(int stationNum)
        {
            IList<CodeInfo> parr;
            switch (stationNum)
            {
                case 1:
                    parr = PublicObject.arrCode1; break;
                case 2:
                    parr = PublicObject.arrCode2; break;
                case 3:
                    parr = PublicObject.arrCode3; break;
                case 4:
                    parr = PublicObject.arrCode4; break;
                default:
                    parr = PublicObject.arrCode1; break;
            }

            if (parr.Count == 0)
            {
                return 1;
            }
            else
                return parr.Max(u => u.serialNumber2) + 1;
            
        }

        public static CodeInfo GetParent(CodeInfo son, ref string strMsg)
        {
            strMsg = string.Empty;

            if (PublicObject.CurTask.tagLevel <= son.stationNumber)
            {
                strMsg = string.Format("码级别必须小于包装层次：包装层次={0}，码级别={1}", PublicObject.CurTask.tagLevel,
                    son.stationNumber);

                return null;
            }
            int[] ratios = GetCurLevelRatios();
            int idxSon = FindCodePos(son);

            if (idxSon<0)
            {
                strMsg = string.Format("未找到子码");

                return null;
            }

            int idxPrt = idxSon / ratios[PublicObject.CurTask.tagLevel-son.stationNumber-1];

            
            switch (son.stationNumber)
            {
                case 1:
                    if (idxPrt>=PublicObject.arrCode2.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, PublicObject.arrCode2.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return PublicObject.arrCode2[idxPrt];
                    }
                    
                case 2:
                    if (PublicObject.bSecond)
                    {
                        idxSon = FindCodePos2(son);
                        if (idxSon < 0)
                        {
                            strMsg = string.Format("未二次扫描，无法关联到父码");

                            return null;
                        }

                        idxPrt = idxSon / ratios[PublicObject.CurTask.tagLevel - son.stationNumber - 1];

                    }

                    if (idxPrt >= PublicObject.arrCode3.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, PublicObject.arrCode3.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return PublicObject.arrCode3[idxPrt];
                    }

                case 3:
                    if (idxPrt >= PublicObject.arrCode4.Count)
                    {
                        strMsg = string.Format("子码待包装，无法关联到父码：子码序号={0}，已包装数量={1}",
                            idxSon + 1, PublicObject.arrCode4.Count * ratios[0]);

                        return null;
                    }
                    else
                    {
                        return PublicObject.arrCode4[idxPrt];
                    }
                default:
                    strMsg = string.Format("码级别必须小于4：码级别={0}", son.stationNumber);
                    return null;
            }
        }
        public static CodeInfo GetParent(string son, ref string strMsg)
        {
            CodeInfo ci = FindCode(son);

            if (ci==null)
            {
                strMsg = "码未入库";
                return null;
            }

            return GetParent(ci, ref strMsg);
        }

        /// <summary>
        /// 获取本包装子数据，比如三级关联，获取某二级包装的子码数据
        /// </summary>
        /// <param name="one"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static List<CodeInfo> GetLevelSonPackageCodes(CodeInfo parentCode, ref string strMsg)
        {
            int idx = FindCodePos(parentCode);

            if (idx<0)
            {
                strMsg = "码不存在";
                return null;
            }

            int[] ratios = AppHelper.GetLevelRatios(PublicObject.CurTask.tagRatio);
            int ratio32 = 0, ratio21 = 0, ratio43 = 0;

            switch (PublicObject.CurTask.tagLevel)
            {
                case 2:
                    ratio21 = ratios[0];
                    break;
                case 3:
                    ratio32 = ratios[0];
                    ratio21 = ratios[1];

                    break;
                case 4:
                    ratio43 = ratios[0];
                    ratio32 = ratios[1];
                    ratio21 = ratios[2];
                    break;

            }

            switch (parentCode.stationNumber)
            {
                case 1:
                    return new List<CodeInfo>(new CodeInfo[] { parentCode });
                case 2:
                    return FindArrayByPos1(1, idx* ratio21, ratio21);
                case 3:
                    if (PublicObject.bSecond)
                    {
                        return FindArrayByPos2(idx * ratio32, ratio32);
                    }
                    else
                    {
                        return FindArrayByPos1(2, idx * ratio32, ratio32);
                    }
                    
                case 4:
                    return FindArrayByPos1(3, idx * ratio43, ratio43);
                default:
                    return null;
            }
        }


        /// <summary>
        /// 获取整包装数据
        /// </summary>
        /// <param name="one"></param>
        /// <param name="strMsg"></param>
        /// <returns></returns>
        public static List<CodeInfo> GetWholePackageCodes(CodeInfo one, ref string strMsg)
        {
            //获取顶级包装码
            CodeInfo parent = one;

            while (parent.stationNumber!=PublicObject.CurTask.tagLevel)
            {
                parent = GetParent(parent, ref strMsg);

                if (parent == null)
                {
                    return null;
                }
            }

            switch (parent.stationNumber)
            {
                case 1:
                    return new List<CodeInfo>(new CodeInfo[] { one});
                case 2:
                    return GetWholePackageCodes2(one, ref strMsg);
                case 3:
                    return GetWholePackageCodes3(one, ref strMsg);
                case 4:
                    return GetWholePackageCodes4(one, ref strMsg);
                default:
                    return null;
            }
        }


        private static List<CodeInfo> GetWholePackageCodes2(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio21 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 2];
            int idx = FindCodePos(one);

            //包装内一级码
            codes.AddRange(FindArrayByPos1(1, idx*ratio21, ratio21));
            codes.Add(one);

            return codes;
        }

        private static List<CodeInfo> GetWholePackageCodes3(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio32 = GetCurLevelRatios()[PublicObject.CurTask.tagLevel - 3];

            int idx = FindCodePos(one);

            //包装内二级码
            List<CodeInfo> codes2 = FindArrayByPos2(idx * ratio32, ratio32);
            for (int i = 0; i < codes2.Count; i++)
            {
                codes.AddRange(GetWholePackageCodes2(codes2[i], ref strMsg));
            }
            
            codes.Add(one);

            return codes;
        }

        private static List<CodeInfo> GetWholePackageCodes4(CodeInfo one, ref string strMsg)
        {
            List<CodeInfo> codes = new List<CodeInfo>();
            int ratio43 = GetCurLevelRatios()[0];

            int idx = FindCodePos(one);

            //包装内三级码
            List<CodeInfo> codes3 = FindArrayByPos1(3, idx * ratio43, ratio43);

            for (int i = 0; i < codes3.Count; i++)
            {
                codes.AddRange(GetWholePackageCodes3(codes3[i], ref strMsg));
            }

            codes.Add(one);

            return codes;
        }

        public static int GetScanTwiceQty()
        {
            return PublicObject.arrCode2.Count(s=> 
            {
                return s.serialNumber2 > 0;
            });
        }

        public static int GetUnpackQty()
        {
            ProductionTask ws = PublicObject.CurTask;

            if (ws.tagLevel == 1)
            {
                return 0;
            }
            else if (ws.tagLevel == 2)
            {
                int ratio21 =  GetCurRatios()[1];

                if (ratio21*PublicObject.arrCode2.Count > PublicObject.arrCode1.Count)
                {
                    return 0;
                }
                else
	            {
                    return PublicObject.arrCode1.Count - ratio21 * PublicObject.arrCode2.Count;
	            }
                
            }
            else if (ws.tagLevel == 3)
            {
                int ratio31 = GetCurRatios()[2];

                if (ratio31 * PublicObject.arrCode3.Count > PublicObject.arrCode1.Count)
                {
                    return 0;
                }
                else
                {
                    return PublicObject.arrCode1.Count - ratio31 * PublicObject.arrCode3.Count;
                }
            }
            else if (ws.tagLevel == 4)
            {
                int ratio41 = GetCurRatios()[3];

                if (ratio41 * PublicObject.arrCode4.Count > PublicObject.arrCode1.Count)
                {
                    return 0;
                }
                else
                {
                    return PublicObject.arrCode1.Count - ratio41 * PublicObject.arrCode4.Count;
                }
            }
            else
            {
                return 0;
            }
        }

        public static int GetZeroQty()
        {
            ProductionTask ws = PublicObject.CurTask;

            if (ws.tagLevel == 1)
            {
                return 0;
            }
            else
            {
                int ratio21 = GetCurLevelRatios()[ws.tagLevel-2];

                if (ratio21 * PublicObject.arrCode2.Count > PublicObject.arrCode1.Count)
                {
                    return PublicObject.arrCode1.Count % ratio21;
                }
                else
                {
                    return 0;
                }

            }
        }

        public static int GetZeroAllQty()
        {
            ProductionTask ws = PublicObject.CurTask;

            if (ws.tagLevel == 1)
            {
                return 0;
            }
            else if (ws.tagLevel == 2)
            {
                int ratio21 = GetCurRatios()[1];

                if (ratio21 * PublicObject.arrCode2.Count > PublicObject.arrCode1.Count)
                {
                    return PublicObject.arrCode1.Count % ratio21;
                }
                else
                {
                    return 0;
                }

            }
            else if (ws.tagLevel == 3)
            {
                int ratio31 = GetCurRatios()[2];

                if (ratio31 * PublicObject.arrCode3.Count > PublicObject.arrCode1.Count)
                {
                    return PublicObject.arrCode1.Count % ratio31;
                }
                else
                {
                    return 0;
                }
            }
            else if (ws.tagLevel == 4)
            {
                int ratio41 = GetCurRatios()[3];

                if (ratio41 * PublicObject.arrCode4.Count > PublicObject.arrCode1.Count)
                {
                    return PublicObject.arrCode1.Count % ratio41;
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;
            }
        }

        public static int GetNormalQty()
        {
            ProductionTask ws = PublicObject.CurTask;

            if (ws.tagLevel == 1)
            {
                return PublicObject.arrCode1.Count;
            }
            else if (ws.tagLevel == 2)
            {
                int ratio21 = GetCurRatios()[1];

                if (ratio21 * PublicObject.arrCode2.Count > PublicObject.arrCode1.Count)
                {
                    return (PublicObject.arrCode1.Count / ratio21) * ratio21;
                }
                else
                {
                    return ratio21 * PublicObject.arrCode2.Count;
                }

            }
            else if (ws.tagLevel == 3)
            {
                int ratio31 = GetCurRatios()[2];

                if (ratio31 * PublicObject.arrCode3.Count > PublicObject.arrCode1.Count)
                {
                    return (PublicObject.arrCode1.Count / ratio31)*ratio31;
                }
                else
                {
                    return ratio31 * PublicObject.arrCode3.Count;
                }
            }
            else if (ws.tagLevel == 4)
            {
                int ratio41 = GetCurRatios()[3];

                if (ratio41 * PublicObject.arrCode4.Count > PublicObject.arrCode1.Count)
                {
                    return (PublicObject.arrCode1.Count / ratio41)*ratio41;
                }
                else
                {
                    return ratio41 * PublicObject.arrCode4.Count;
                }
            }
            else
            {
                return PublicObject.arrCode1.Count;
            }
        }

        //public static List<CodeInfo> GetPackageSons(CodeInfo parent, ref string strMsg)
        //{
        //    strMsg = string.Empty;

        //    if (parent.stationNumber < 2 || parent.stationNumber>PublicObject.CurTask.tagLevel)
        //    {
        //        strMsg = string.Format("码级别必须>1且≤包装层次：包装层次={0}，码级别={1}", PublicObject.CurTask.tagLevel,
        //            parent.stationNumber);

        //        return null;
        //    }


        //}

        #endregion

            /// <summary>
            /// 零箱剩余数据，保证次级定包装达到整包装的零箱，只支持三级和四级关联
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
        public static bool ZeroRemain(ref string msg)
        {
            int tagLevel = PublicObject.CurTask.tagLevel;

            if (tagLevel < 3)
            {
                msg = "只支持三级和四级关联";
                return false;
            }

            int[] ratios = AppHelper.GetLevelRatios(PublicObject.CurTask.tagRatio);
            int ratio32 = 0, ratio21 = 0, ratio43 = 0;

            switch (PublicObject.CurTask.tagLevel)
            {
                case 3:
                    ratio32 = ratios[0];
                    ratio21 = ratios[1];

                    break;
                case 4:
                    ratio43 = ratios[0];
                    ratio32 = ratios[1];
                    ratio21 = ratios[2];
                    break;
                default:
                    msg = "包装级别不支持：级别=" + tagLevel;
                    return false;

            }

            int nTwo = PublicObject.arrCode1.Count / ratio21;
            nTwo = PublicObject.arrCode2.Count > nTwo ? nTwo : PublicObject.arrCode2.Count;
            try
            {
                PublicObject.arrCode2.RemoveRange(nTwo, PublicObject.arrCode2.Count - nTwo);
            }
            catch (Exception)
            {

            }
               

            for (int i = PublicObject.arrCode1.Count-1; i >= nTwo* ratio21; i--)
            {
                try
                {
                    PublicObject.arrCode1.RemoveAt(i);
                }
                catch (Exception)
                {

                }
                    
            }


            return true;

        }
    }
}
